use std::cell::{RefCell, RefMut};
use std::ops::{Deref, Index};
use std::rc::Rc;
use std::thread::Thread;

use crate::class_file::byte_data_reader::ByteDataReader;
use crate::get_val_from_vm_val_enum;
use crate::heap::vm_heap::VMHeap;
use crate::instruction::instruction::Instruction;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::{VMValChar, VMValEnum, VMValLong};

pub struct lstore_0 {}

impl Instruction for lstore_0 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _lstore(0, frame);
    }

    fn to_string(&self) -> String {
        String::from("lstore_0")
    }
}

pub struct lstore_1 {}

impl Instruction for lstore_1 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _lstore(1, frame);
    }

    fn to_string(&self) -> String {
        String::from("lstore_1")
    }
}

pub struct lstore_2 {}

impl Instruction for lstore_2 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _lstore(2, frame);
    }

    fn to_string(&self) -> String {
        String::from("lstore_2")
    }
}


pub struct lstore_3 {}

impl Instruction for lstore_3 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _lstore(3, frame);
    }

    fn to_string(&self) -> String {
        String::from("lstore_3")
    }
}

pub struct lstore {
    index: u8,
}

impl Instruction for lstore {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.deref().borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _lstore(self.index, frame);
    }

    fn to_string(&self) -> String {
        String::from("lstore")
    }
}

fn _lstore(index: u8, frame: Rc<RefCell<VMFrame>>) {
    frame.borrow().local_vars.borrow_mut().insert(index, VMValEnum::VMValLong {
        val: frame.borrow().pop_long_from_stack()
    });
}

pub struct istore_0 {}

impl Instruction for istore_0 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _istore(0, frame);
    }

    fn to_string(&self) -> String {
        String::from("istore_0")
    }
}

pub struct istore_1 {}

impl Instruction for istore_1 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _istore(1, frame);
    }

    fn to_string(&self) -> String {
        String::from("istore_1")
    }
}

pub struct istore_2 {}

impl Instruction for istore_2 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _istore(2, frame);
    }

    fn to_string(&self) -> String {
        String::from("istore_2")
    }
}


pub struct istore_3 {}

impl Instruction for istore_3 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _istore(3, frame);
    }

    fn to_string(&self) -> String {
        String::from("istore_3")
    }
}

pub struct istore {
    index: u8,
}

impl Instruction for istore {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.deref().borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _istore(self.index, frame);
    }

    fn to_string(&self) -> String {
        String::from("istore")
    }
}

fn _istore(index: u8, frame: Rc<RefCell<VMFrame>>) {
    let rw_frame = frame.borrow_mut();
    rw_frame.local_vars.borrow_mut().insert(index, VMValEnum::VMValInteger {
        val: rw_frame.pop_integer_from_stack()
    });
}


pub struct astore_0 {}

impl Instruction for astore_0 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _astore(0, frame);
    }


    fn to_string(&self) -> String {
        String::from("astore_0")
    }
}

pub struct astore_1 {}

impl Instruction for astore_1 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _astore(1, frame);
    }

    fn to_string(&self) -> String {
        String::from("astore_1")
    }
}

pub struct astore_2 {}

impl Instruction for astore_2 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _astore(2, frame);
    }

    fn to_string(&self) -> String {
        String::from("astore_2")
    }
}


pub struct astore_3 {}

impl Instruction for astore_3 {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _astore(3, frame);
    }

    fn to_string(&self) -> String {
        String::from("astore_3")
    }
}

pub struct astore {
    pub index: u8,
}

impl Instruction for astore {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.deref().borrow_mut().read_u8();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        _astore(self.index, frame);
    }

    fn to_string(&self) -> String {
        String::from("astore")
    }
}

fn _astore(index: u8, frame: Rc<RefCell<VMFrame>>) {
    let rw_frame = frame.borrow_mut();
    rw_frame.local_vars.borrow_mut().insert(index, VMValEnum::VMValRef {
        val: rw_frame.pop_ref_from_stack()
    });
}


pub struct castore {}

impl Instruction for castore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let ro_frame = frame.borrow();
        let mut rw_operand_stack = ro_frame.operand_stack.borrow_mut();
        let val_enum = {
            let temp_val_enum = rw_operand_stack.pop().unwrap();
            match temp_val_enum {
                VMValEnum::VMValChar { val } => { VMValEnum::VMValChar { val } }
                VMValEnum::VMValShort { val } => {
                    VMValEnum::VMValChar { val: VMValChar { val: val.num as u16 } }
                }
                VMValEnum::VMValByte { val } => {
                    VMValEnum::VMValChar { val: VMValChar { val: val.num as u16 } }
                }
                _ => { panic!("{},{},类型转化异常", file!(), line!()); }
            }
        };
        let index_enum = rw_operand_stack.pop().unwrap();
        let arr_enum = rw_operand_stack.pop().unwrap();

        let index = match index_enum {
            VMValEnum::VMValByte { val } => { val.num as i32 }
            VMValEnum::VMValShort { val } => { val.num as i32 }
            VMValEnum::VMValInteger { val } => { val.num }
            _ => {
                panic!("{},{},{}", file!(), line!(), "数组索引异常");
            }
        };
        let arr_ref = get_val_from_vm_val_enum!(&arr_enum, VMValRef);
        let arr = VMHeap::get_vmobject(arr_ref.clone()).unwrap();
        assert!(arr.is_arr, "类型不匹配，此指令仅支持数组");
        if arr.arr_len <= index {
            panic!("{},{},{}", file!(), line!(), "数组越界");
        }
        arr.slots.borrow_mut()[index as usize] = val_enum;
    }

    fn to_string(&self) -> String {
        String::from("castore")
    }
}


pub struct bastore {}

impl Instruction for bastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("bastore")
    }
}


pub struct sastore {}

impl Instruction for sastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("sastore")
    }
}


pub struct iastore {}

impl Instruction for iastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("iastore")
    }
}


pub struct lastore {}

impl Instruction for lastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("lastore")
    }
}

pub struct fastore {}

impl Instruction for fastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("fastore")
    }
}


pub struct dastore {}

impl Instruction for dastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("dastore")
    }
}


pub struct aastore {}

impl Instruction for aastore {
    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        arr_store(frame, thread);
    }

    fn to_string(&self) -> String {
        String::from("aastore")
    }
}

fn arr_store(frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
    let ro_frame = frame.borrow();
    let mut rw_operand_stack = ro_frame.operand_stack.borrow_mut();
    let val_enum = rw_operand_stack.pop().unwrap();
    let index_enum = rw_operand_stack.pop().unwrap();
    let arr_enum = rw_operand_stack.pop().unwrap();

    let index = VMValEnum::convert2integer(&index_enum).num;
    let arr_ref = get_val_from_vm_val_enum!(&arr_enum, VMValRef);
    let arr = VMHeap::get_vmobject(arr_ref.clone()).unwrap();
    assert!(arr.is_arr, "类型不匹配，此指令仅支持数组");
    if arr.arr_len <= index {
        panic!("{},{},{}", file!(), line!(), "数组越界");
    }
    arr.slots.borrow_mut()[index as usize] = val_enum;
}














